#pragma once
#include <iostream>
#include <poll.h>
#include <sys/time.h>
#include "Socket.hpp"

using namespace std;
static const int default_fd = -1;
static const int fd_num_max = 64;
int non_event = 0;

//底层结构: 位图
class PollServer
{
private:
    Socket _listensock;
    uint16_t _port = 8080;
    struct pollfd _event_fds[fd_num_max];

public:
    PollServer(uint16_t port)
        :_port(port)
    {
        for(int i = 0; i < fd_num_max; i++)
        {
            _event_fds[i].fd = default_fd;
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;
        }
    }

    ~PollServer()
    {
        _listensock.Close();
    }

public:
    bool Init();
    void Start();                       //监听文件描述符(连接到来 or 资源就绪)
    void SendEvent();                   //根据情况派发事件
    void NewLink();                     //连接到来
    void ParseData(int fd, int pos);    //资源就绪

};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool PollServer::Init()
{
    _listensock.Create();
    _listensock.Bind(_port);
    _listensock.Listen();

    return true;
}

void PollServer::Start()
{
    int listensock = _listensock.GetSockfd();
    _event_fds[0].fd = _listensock.GetSockfd();
    _event_fds[0].events = POLLIN;//只关心可读
    int timeout = 3000;

    while(1)
    {
        int n = poll(_event_fds, fd_num_max, timeout);
        switch (n)
        {
        case 0:
            cout << "time out" << endl;
            break;
        case -1:
            cerr << "poll error" << endl;
            break;
        default:
            //事件就绪: 可能是新连接 or 可以读取数据了
            cout << "get a new link" << endl;   
            SendEvent(); 
            break;
        }
    }
}

// io = 等 + 拷贝
//所有合法的文件描述符在fd_arry中, select返回后就绪的文件描述符在rfds中
void PollServer::SendEvent()
{
    for(int i = 0; i < fd_num_max; i++)
    {
        // 检查就绪的文件描述符
        int fd = _event_fds[i].fd;
        if(fd == default_fd)continue;

        if(_event_fds[i].revents & POLLIN)//可读事件就绪 or 新连接来了
        {
            //获取新连接
            if(fd == _listensock.GetSockfd())
            {
                NewLink();
            }
            else //可以读数据了
            {
                ParseData(fd,i);
                cout << "ParseData" << endl;
            }
        }
    }
}

void PollServer::NewLink()
{
    std:string client_ip;
    uint16_t client_port;
    int newsocket = _listensock.Accept(&client_ip, &client_port);
    if(newsocket < 0)return;
    cout << "accept success--" << "client_ip: " << client_ip << "client_port: "  << client_port << endl;

    //找到能放的位置
    int pos = 1;
    for( ; pos = 1 < fd_num_max; pos++)
    {
        if(_event_fds[pos].fd != default_fd)
            continue;
        else 
            break;
    }

    //满了--放不下了扩容 or 退出
    if(pos == fd_num_max)
    {
        cout << "server is full" << endl;
        close(newsocket);
        //使用vector可以扩容...
    }
    else
    {
        _event_fds[pos].fd = newsocket;
        _event_fds[pos].events = POLLIN;        //设置关心可读
        _event_fds[pos].revents = non_event;
    }
}

void PollServer::ParseData(int fd, int i)
{
    char buffer[1024];
    ssize_t n =  read(_event_fds[i].fd, buffer, sizeof(buffer) - 1); //我们不一定能保证读取的数据保证--协议定制--需要处理
    if(n > 0)
    {
        buffer[n] = 0;
        cout << "get a message: " << buffer <<endl;
    }
    else if(n == 0)
    {
        cout << "client quit, fd is " << fd << endl;
        close(fd);
        _event_fds[i].fd = default_fd;    
    }
}

